using System;
using System.Collections.Generic;
using System.Text;
using IGGCore;
using System.Drawing;
using System.Windows.Forms;
using System.IO;
using System.Threading;
using System.Net;
using IGGWindowApp.Data;

namespace IGGWindowApp
{
    /// <summary>
    /// The manager of the IGG window application
    /// </summary>
    public class FormManager
    {
        private MainForm m_mainForm;
        private MainFormBeta m_mainFormBeta;

        private MainChannel m_mainChannel;
        private Thread m_initThread;
        private Thread m_newsThread;
        private Thread m_updateThread;
        private StadiumParser m_stadiumParser;
        private MODES m_currentMode = MODES.FIELD;

        private bool m_running = true;
        private bool m_updating = false;
        private bool m_initialized = false;
        private bool m_statsLoaded = false;
        private bool m_standingsLoaded = false;
        private DateTime m_boardTime = DateTime.Now;

        /// <summary>
        /// The IGG window main form (used by the Program class to start the app)
        /// </summary>
        public MainForm MainForm
        {
            get { return m_mainForm; }
        }

        public MainFormBeta MainFormBeta
        {
            get { return m_mainFormBeta; }
        }

        /// <summary>
        /// Main constructor
        /// </summary>
        public FormManager()
        {
            m_mainForm = new MainForm();
            m_mainFormBeta = new MainFormBeta();
            m_mainChannel = new MainChannel();
            m_stadiumParser = new StadiumParser();

            m_mainForm.GameSelected += new MainForm.GameSelectedHandler(m_mainForm_SelectedGameChange);
            m_mainForm.MainFormLoaded += new System.EventHandler(m_mainForm_MainFormLoaded);
            m_mainForm.MainFormClosing += new EventHandler(m_mainForm_MainFormClosing);
            m_mainForm.StadiumUpdateRequested += new EventHandler(m_mainForm_StadiumUpdateRequested);
            m_mainForm.modeChanged += new MainForm.ModeChangeHandler(m_mainForm_modeChanged);
            m_mainForm.BoxSelected += new IGGWindowApp.MainForm.BoxSelectedHandler(m_mainForm_BoxSelected);
            m_mainForm.BoxDayChanged += new IGGWindowApp.MainForm.BoxDayChangeddHandler(m_mainForm_BoxDayChanged);
        }

        private void m_mainForm_BoxDayChanged(bool before)
        {
            if (before)
            {
                m_boardTime = m_boardTime.AddDays(-1);
            }
            else
            {
                m_boardTime = m_boardTime.AddDays(-1);
            }
            m_mainChannel.RefreshScoreboardDated(m_boardTime);
            m_mainForm.Invoke(m_mainForm.mySwitchMode, new object[] { m_currentMode, m_mainChannel.ScoreBoardDated });
        }

        private void m_mainForm_BoxSelected(Game game)
        {
            Player[] stars = null;
            if (game != null)
            {
                m_mainChannel.UpdateBoxscore(m_boardTime, game);
                stars = ThreeStarsCalculator.GetThreeStarPlayers(game, false);
            }
            else
            {
                m_mainChannel.UpdateAllBoxscores(m_boardTime, m_mainChannel.ScoreBoardDated);
                stars = ThreeStarsCalculator.GetThreeStarPlayers(m_mainChannel.ScoreBoardDated.GamesList.Games);
            }
            if (stars[0] != null)
            {
                stars[0].Pic = DownloadPlayerPicture(stars[0].Id);
                stars[1].Pic = DownloadPlayerPicture(stars[1].Id);
                stars[2].Pic = DownloadPlayerPicture(stars[2].Id);
                m_mainForm.Invoke(m_mainForm.myUpdateStars, new object[] { stars });
            }
        }

        /// <summary>
        /// Manage a change of Mode
        /// </summary>
        private void m_mainForm_modeChanged(MODES newmode)
        {
            m_currentMode = newmode;
            object data = null;
            switch(m_currentMode)
            {
                case MODES.LINEUP:
                    m_mainChannel.UpdateTeamAlignment(DateTime.Now);
                    m_mainChannel.UpdateBoxscore(DateTime.Now);
                    data = m_mainChannel.ScoreBoard.SelectedGame;
                    break;
                case MODES.STATS:
                    if (m_statsLoaded == false)
                    {
                        m_mainChannel.UpdateStatistics();
                        m_statsLoaded = true;
                    }
                    data = m_mainChannel.ScoreBoard;
                    break;
                case MODES.SCOREBOARDS:
                    if (m_mainChannel.ScoreBoardDated == null)
                    {
                        m_mainChannel.ScoreBoardDated = m_mainChannel.ScoreBoard;
                    }
                    data = m_mainChannel.ScoreBoardDated;
                    break;
                case MODES.FIELD:
                    data = m_mainChannel.ScoreBoard.SelectedGame;
                    break;
                case MODES.NEWS:
                    data = m_mainChannel.ScoreBoard.News;
                    break;
                case MODES.STANDINGS:
                    if (m_standingsLoaded == false)
                    {
                        m_mainChannel.UpdateStandings();
                        m_standingsLoaded = true;
                    }
                    data = m_mainChannel.ScoreBoard;
                    break;
            }
            m_mainForm.Invoke(m_mainForm.mySwitchMode, new object[] { m_currentMode, data });
        }

        /// <summary>
        /// Initialize the online data once the main form is loaded
        /// </summary>
        private void m_mainForm_MainFormLoaded(object sender, EventArgs e)
        {
            m_initThread = new Thread(new ThreadStart(InitializeWindowApp));
            m_initThread.Start();
        }

        /// <summary>
        /// Initialize the window application
        /// </summary>
        private void InitializeWindowApp()
        {
            Log("Initializing basic layout...");
            m_mainForm.Invoke(m_mainForm.myInitBasicLayout, new object[] { });
            UpdateMainForm();
            Thread.Sleep(200);
            m_newsThread = new Thread(new ThreadStart(InitializeNews));
            m_newsThread.Priority = ThreadPriority.BelowNormal;
            m_newsThread.Start();

            m_updateThread = new Thread(new ThreadStart(UpdateMainApplicationData));
            m_updateThread.Priority = ThreadPriority.BelowNormal;
            m_updateThread.Start();
        }

        /// <summary>
        /// Update the main application
        /// </summary>
        private void UpdateMainApplicationData()
        {
            while (m_running)
            {
                Thread.Sleep(120000);
                UpdateMainForm();
            }
        }

        /// <summary>
        /// Initialize the news in a thread
        /// </summary>
        private void InitializeNews()
        {
            if (LoadNews() == false)
            {
                Log("Unable to load news from mlb.com. Try later.");
                return;
            }
            Log("Loading history bits...");
            m_mainChannel.UpdateHistory();
            Log("Updating news panel...");

            if (m_running && m_mainChannel.ScoreBoard.News.Count > 0)
            {
                m_mainForm.Invoke(m_mainForm.myUpdateNews, new object[] { m_mainChannel.ScoreBoard.News, m_mainChannel.ScoreBoard.History });
            }
        }


        /// <summary>
        /// Select a game and update the main form
        /// </summary>
        private void UpdateMainForm()
        {
            while (m_updating)
            {
                Thread.Sleep(1000);
            }
            m_updating = true;
            if (m_mainChannel.ScoreBoard.SelectedGame == null || m_mainChannel.ScoreBoard.SelectedGame.Status.Indicator.Category != Indicator.IndicatorCategoy.TERMINATED)
            {
                if (LoadMLBScoreboard() == false)
                {
                    Log("The online mlb.com scoreboard cannot be loaded. Try later.");
                    return;
                }
                Log("Updating game buttons...");
                m_mainForm.Invoke(m_mainForm.myUpdateGameList, new object[] { m_mainChannel.ScoreBoard.GamesList });
            }
            Indicator.IndicatorCategoy gameCategory = Indicator.IndicatorCategoy.TERMINATED;
            if (m_mainChannel.ScoreBoard.SelectedGame != null)
            {
                gameCategory = m_mainChannel.ScoreBoard.SelectedGame.Status.Indicator.Category;
            }
            if (m_initialized == false)
            {
                Log("Activating the Around The League Ticker...");
                m_mainForm.Invoke(m_mainForm.myActivateAroundLeague, new object[] { });
            }

            if (m_mainChannel.ScoreBoard.SelectedGame != null && LoadGameBoxscore() == false)
            {
                Log("The selected game boxscore cannot be loaded. Try later.");
                return;
            }
            if (m_mainChannel.ScoreBoard.SelectedGame != null)
            {
                Log("Updating boxscore panels...");
                m_mainForm.Invoke(m_mainForm.myUpdateBoxscore, new object[] { m_mainChannel.ScoreBoard.SelectedGame });

                Log("The selected game is " + m_mainChannel.ScoreBoard.SelectedGame.AwayTeam.Name
                    + " vs " + m_mainChannel.ScoreBoard.SelectedGame.HomeTeam.Name + ".");
                m_mainForm.Invoke(m_mainForm.myUpdateSelectedGame, new object[] { m_mainChannel.ScoreBoard.SelectedGame });
                Log("Parsing the stadium files...");
                WindowStadium stadium = m_stadiumParser.GetStadium(m_mainChannel.ScoreBoard.SelectedGame.Stadium);
                Log("Updating stadium information...");
                m_mainForm.Invoke(m_mainForm.myUpdateStadium,
                    new object[] { stadium, m_mainChannel.ScoreBoard.SelectedGame });
            }
            if (m_initialized == false)
            {
                Log("Enabling game buttons...");
                m_mainForm.Invoke(m_mainForm.myEnableGameButtons, new object[] { });
            }

            if (gameCategory == Indicator.IndicatorCategoy.IN_PROGRESS)
            {
                if (LoadGameAlignment() == false)
                {
                    Log("The selected game alignment cannot be loaded. Try later.");
                    return;
                }

                Log("Retrieving players pictures...");
                string battingCity = m_mainChannel.ScoreBoard.SelectedGame.AwayTeam.Name;
                string pitchingCity = m_mainChannel.ScoreBoard.SelectedGame.HomeTeam.Name;
                if (m_mainChannel.ScoreBoard.SelectedGame.Status.InningTop == false)
                {
                    battingCity = m_mainChannel.ScoreBoard.SelectedGame.HomeTeam.Name;
                    pitchingCity = m_mainChannel.ScoreBoard.SelectedGame.AwayTeam.Name;
                }
                Image pitcherPic = PlayerParser.GetPlayerImage(m_mainChannel.ScoreBoard.SelectedGame.Status.CurrentPitcher.FirstName,
                                m_mainChannel.ScoreBoard.SelectedGame.Status.CurrentPitcher.LastName, pitchingCity);
                Image batterPic = PlayerParser.GetPlayerImage(m_mainChannel.ScoreBoard.SelectedGame.Status.CurrentBatter.FirstName,
                                m_mainChannel.ScoreBoard.SelectedGame.Status.CurrentBatter.LastName, battingCity);

                Log("Updating players pictures...");
                m_mainForm.Invoke(m_mainForm.mySetPlayersPictures, new object[] { batterPic, pitcherPic });
            }

            if (m_currentMode == MODES.FIELD)
            {
                Log("Showing the stadium...");
                m_mainForm.Invoke(m_mainForm.myShowStadium, new object[] { });

                if (gameCategory == Indicator.IndicatorCategoy.IN_PROGRESS)
                {
                    Log("Showing the players...");
                    m_mainForm.Invoke(m_mainForm.mySetPlayers, new object[] { m_mainChannel.ScoreBoard.SelectedGame });
                }
            }
            m_initialized = true;
            m_updating = false;
        }

        /// <summary>
        /// Log something
        /// </summary>
        private void Log(string log)
        {
            if (m_running)
            {
                m_mainForm.Invoke(m_mainForm.myAddLog, new object[] { log });
            }
        }

        /// <summary>
        /// Load mlb scoreboard
        /// </summary>
        private bool LoadMLBScoreboard()
        {
            bool success = false;
            int currentTry = 1;
            int delay = 1000;
            while (success == false && currentTry <= WindowConstants.MAX_TRIES)
            {
                try
                {
                    Thread.Sleep(delay);
                    Log("Loading mlb.com scoreboard...");
                    if (m_mainChannel.ScoreBoard.SelectedGame == null)
                    {
                        m_mainChannel.RefreshScoreboard(DateTime.Now, null);
                    }
                    else
                    {
                        m_mainChannel.RefreshScoreboard(DateTime.Now, m_mainChannel.ScoreBoard.SelectedGame.Id);
                    }
                    success = true;
                    Log("The scoreboard has been successfully parsed.");
                }
                catch (Exception ex)
                {
                    Log(ex.Message);
                    delay = (delay * 2);
                }
                currentTry++;
            }
            return success;
        }

        /// <summary>
        /// Load game boxscore
        /// </summary>
        private bool LoadGameBoxscore()
        {
            bool success = false;
            int currentTry = 1;
            int delay = 1000;
            while (success == false && currentTry <= WindowConstants.MAX_TRIES)
            {
                try
                {
                    Thread.Sleep(delay);
                    Log("Retrieving selected game boxscore...");
                    m_mainChannel.UpdateBoxscore(DateTime.Now);
                    success = true;
                    Log("The boxscore has been successfully parsed.");
                }
                catch (Exception ex)
                {
                    Log(ex.Message);
                    delay = (delay * 2);
                }
                currentTry++;
            }
            return success;
        }

        /// <summary>
        /// Load game alignment
        /// </summary>
        private bool LoadGameAlignment()
        {
            bool success = false;
            int currentTry = 1;
            int delay = 1000;
            while (success == false && currentTry <= WindowConstants.MAX_TRIES)
            {
                try
                {
                    Thread.Sleep(delay);
                    Log("Retrieving selected game team alignment...");
                    m_mainChannel.UpdateTeamAlignment(DateTime.Now);
                    success = true;
                    Log("The alignment has been successfully parsed.");
                }
                catch (Exception ex)
                {
                    Log(ex.Message);
                    delay = (delay * 2);
                }
                currentTry++;
            }
            return success;
        }

        /// <summary>
        /// Load news
        /// </summary>
        private bool LoadNews()
        {
            bool success = false;
            int currentTry = 1;
            int delay = 1000;
            while (success == false && currentTry <= WindowConstants.MAX_TRIES)
            {
                try
                {
                    Thread.Sleep(delay);
                    Log("Loading mlb.com news...");
                    m_mainChannel.UpdateNews(false);
                    success = true;
                    Log("The news has been successfully loaded.");
                }
                catch (Exception ex)
                {
                    Log(ex.Message);
                    delay = (delay * 2);
                }
                currentTry++;
            }
            return success;
        }

        /// <summary>
        /// Manage a change of selected game from the Main Form
        /// </summary>
        private void m_mainForm_SelectedGameChange(Game game)
        {
            m_mainChannel.ScoreBoard.SelectedGame = game;
            Thread selectThread = new Thread(new ThreadStart(UpdateMainForm));
            selectThread.Start();
        }

        /// <summary>
        /// Manage the closing of the main form
        /// </summary>
        private void m_mainForm_MainFormClosing(object sender, EventArgs e)
        {
            m_running = false;
            if (m_newsThread != null)
            {
                m_newsThread.Abort();
            }
            if (m_initThread != null)
            {
                m_initThread.Abort();
            }
            if (m_updateThread != null)
            {
                m_updateThread.Abort();
            }
        }

        /// <summary>
        /// Update current stadium. Triggered on a picture double-click
        /// </summary>
        private void m_mainForm_StadiumUpdateRequested(object sender, EventArgs e)
        {
            WindowStadium stadium = m_stadiumParser.GetStadium(m_mainChannel.ScoreBoard.SelectedGame.Stadium);
            m_mainForm.Invoke(m_mainForm.myUpdateStadium,
                new object[] { stadium, m_mainChannel.ScoreBoard.SelectedGame });
        }

        /// <summary>
        /// Download a player picture from the cnssi website
        /// </summary>
        private Image DownloadPlayerPicture(string id)
        {
            Image result = null;
            Stream stream = null;
            try
            {
                WebClient client = new WebClient();
                // 425883.jpg
                stream = client.OpenRead("http://mlb.mlb.com/images/players/mugshot/ph_" + id + WindowConstants.IMAGE_EXTENSION);
                result = new Bitmap(stream);
                stream.Flush();
                stream.Close();

                //string path = Application.StartupPath + WindowConstants.FOLDER_PATH_PLAYERS + "//" + team;
                //if (Directory.Exists(path) == false)
                //{
                //    Directory.CreateDirectory(path);
                //}
                //string filePath = path + "//" + firstName.ToLower() + "_" + lastName.ToLower() + WindowConstants.IMAGE_EXTENSION;
                //result.Save(filePath);
            }
            catch { }
            finally
            {
                if (stream != null)
                {
                    stream.Close();
                    stream = null;
                }
                string path = Application.StartupPath + WindowConstants.FOLDER_PATH_PLAYERS;
                if (result == null)
                {
                    result = new Bitmap(path + WindowConstants.FILE_UNKNOWN_PLAYER_PIC);
                }
            }
            return result;
        }
    }
}
